package cn.tedu.property_management_system.service.Impl;

import cn.tedu.property_management_system.cache.repo.ICompliantRepository;
import cn.tedu.property_management_system.entity.Complaint;
import cn.tedu.property_management_system.entity.ComplaintType;
import cn.tedu.property_management_system.entity.DTO.ComplaintAddNewDTO;
import cn.tedu.property_management_system.entity.VO.ComplaintVO;
import cn.tedu.property_management_system.entity.VO.UserVO;
import cn.tedu.property_management_system.ex.ServiceException;
import cn.tedu.property_management_system.mapper.ComplaintMapper;
import cn.tedu.property_management_system.mapper.ComplaintTypeMapper;
import cn.tedu.property_management_system.mapper.UserMapper;
import cn.tedu.property_management_system.service.*;
import cn.tedu.property_management_system.utils.Constant;
import cn.tedu.property_management_system.utils.JsonResult;
import cn.tedu.property_management_system.utils.SecurityUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static cn.tedu.property_management_system.utils.Constant.HANDLED_STATE;
import static cn.tedu.property_management_system.utils.JsonResult.State.UNAUTHORIZED;
import static cn.tedu.property_management_system.utils.JsonResult.State.UNKNOW_EXCEPTION;

/**
 * @author admin
 */
@Slf4j
@Service
public class ComplaintServiceImpl implements IComplaintService, Constant {

    @Autowired
    private ICompliantRepository compliantRepository;

    @Autowired(required = false)
    private ComplaintMapper complaintMapper;

    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired(required = false)
    private ComplaintTypeMapper complaintTypeMapper;

    @Override
    public PageInfo<ComplaintVO> loadCompliant(Integer pageNum, Integer PageSize) {
        //先进入缓存查询
        //有可能此时缓存已经过期,进入数据库查询,此时就实现了定时更新缓存
        if (compliantRepository.hasPageKey(pageNum)) {
            log.debug("redis执行分页查询,前端传入页数为[{}],每页大小为[{}]",pageNum,PageSize);
            PageInfo<ComplaintVO> pageCache = compliantRepository.getPageCache(pageNum);
            log.debug("分页结果为[{}],条数为[{}]",pageCache,PageSize);
            log.debug("缓存中存在数据,不再进入数据查询【投诉】列表");
            return pageCache;
        }
        log.debug("数据库执行分页查询,前端传入页数为[{}],每页大小为[{}]",pageNum,PageSize);
        PageHelper.startPage(pageNum,PageSize);
        List<ComplaintVO> complaintVOS = complaintMapper.selectAllToComplaintVO();
        PageInfo<ComplaintVO> complaintVOPageInfo = new PageInfo<>(complaintVOS);
        log.debug("[投诉]列表缓存过期，进入数据库查询数据，查询结果为[{}]",complaintVOS);
        //判断数据库中查询结果是否为空,如果结果为true,则证明数据库中也不存在数据,则不用写入缓存
        if (complaintVOS==null) {
            log.debug("[投诉]列表为空,返回null");
            return null;
        }
        //如果结果不为空,则将数据库的数据同步入缓存,实现定时更新,并返回
        log.debug("写入[投诉]分页缓存到redis,当页码[{}]",pageNum);
        compliantRepository.setPageCache(pageNum,complaintVOPageInfo);
        return complaintVOPageInfo;
    }

    @Override
    public void deleteCompliant(int id) {
            int rows = complaintMapper.deleteByPrimaryKey(id);
            if (rows!=1){
                throw new ServiceException(UNKNOW_EXCEPTION,"发生了未知的异常");
            }
    }

    @Override
    public void handleCompliant(int id, int userId) {
            Complaint complaint = new Complaint();
            complaint.setId(id);
            complaint.setClr(userId);
            complaint.setStatus(HANDLED_STATE);
            complaintMapper.updateStatues(complaint);
    }

    @Override
    public List<ComplaintType> loadCompliantType() {
        List<ComplaintType> complaintTypes = complaintTypeMapper.selectAllCompliantType();
        return complaintTypes;
    }

    @Override
    public List<ComplaintVO> screenCompliant(Integer comId, Integer status) {
        List<ComplaintVO> complaintVOS = complaintMapper.selectAllToComplaintVOByStatusAndComId(comId,status);
        return complaintVOS;
    }

    @Override
    public void bathDelete(Integer[] deleteComplaintArr) {
        complaintMapper.deleteByIds(deleteComplaintArr);
        loadCache();
    }

    @Override
    public void bathUpDate(Complaint complaint) {
        complaintMapper.insert(complaint);
        loadCache();
    }

    @Override
    public void bathOutput(HttpServletResponse response) {
        List<ComplaintVO> complaintVOS = complaintMapper.selectAllToComplaintVO();
        try {
            //文件导出response的设置，格式固定
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    java.net.URLEncoder.encode("投诉表明细.xls", "UTF-8"));
            //开启流，传输excel文件
            ServletOutputStream outputStream = response.getOutputStream();
            //设置写出流和写出类
            ExcelWriterBuilder write = EasyExcel.write(outputStream,ComplaintVO.class);
            //代表在文件中创建一个工作表
            ExcelWriterSheetBuilder sheet = write.sheet();
            //实际将工作表写出
            sheet.doWrite(complaintVOS);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void insert(ComplaintAddNewDTO complaintAddNewDTO) {
        log.debug("前端传入添加的投诉信息为:[{}]",complaintAddNewDTO);
        String concurrentUserName = SecurityUtil.getConcurrentUserName();
        Complaint complaint = new Complaint();
        UserVO concurrentUser = userMapper.findByUsername(concurrentUserName);
        complaint.setComId(complaintAddNewDTO.getComId())
                .setRemarks(complaintAddNewDTO.getRemakes())
                .setUrls(complaintAddNewDTO.getImgUrls())
                .setOwerId(concurrentUser.getId().intValue())
                .setComDate(new Date())
                .setStatus(0)
                .setClr(0);
        log.debug("根据投诉值传递对象创建完整投诉对象[{}],并写入数据库",complaint);
        loadCache();
        int row = complaintMapper.insert(complaint);
        if (row!=HANDLE_SUCCESS){
            log.debug("返回受影响行数不为1,抛出异常");
            throw new ServiceException(UNKNOW_EXCEPTION,"服务器忙请稍后重试");
        }
    }

    @Override
    public List<ComplaintVO> loadPersonalCompliant() {
        String concurrentUserName = SecurityUtil.getConcurrentUserName();
        log.debug("当前用户名为[{}]",concurrentUserName);
        List<ComplaintVO> complaintVOS = complaintMapper.selectAllToComplaintVOPersonal(concurrentUserName);
        log.debug("根据当前用户名查询到得投诉列表为:[{}]",complaintVOS);
        return complaintVOS;
    }

    @Override
    public void initCache() {
        loadCache();
    }

    private void loadCache(){
        List<ComplaintVO> complaintVOS = complaintMapper.selectAllToComplaintVO();
        compliantRepository.clear();
        compliantRepository.loadCache(complaintVOS);
    }
}
